package com.sinszm.web.cos;

import cn.hutool.core.thread.ThreadUtil;
import com.qcloud.cos.COSClient;
import com.qcloud.cos.exception.CosClientException;
import com.qcloud.cos.model.*;
import com.qcloud.cos.transfer.*;
import com.sinszm.common.exception.ApiException;
import com.sinszm.common.util.CommonUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.File;
import java.util.concurrent.ExecutorService;

import static java.util.concurrent.Executors.newFixedThreadPool;

/**
 * 执行COS存储操作
 *
 * @author sinszm
 */
@Slf4j
@ConditionalOnExpression("${szm.boot.cos.enable:false}")
@Component
public class CosDao {

    @Resource
    private CosProperties cosProperties;

    @Resource
    private COSClient cosClient;

    @Resource
    private String cosBucketName;

    /**
     * 传输管理器
     *
     * @return 管理器实例
     */
    private TransferManager transferManager() {
        ExecutorService threadPool = newFixedThreadPool(
                cosProperties.getThreadPool() <= 0 ? 1 : cosProperties.getThreadPool()
        );
        return new TransferManager(cosClient, threadPool);
    }

    /**
     * 上传进度
     *
     * @param transfer 进度数据
     */
    private void showTransferProgress(Transfer transfer) {
        log.info(transfer.getDescription());
        do {
            ThreadUtil.sleep(2000);
            TransferProgress progress = transfer.getProgress();
            long soFar = progress.getBytesTransferred();
            long total = progress.getTotalBytesToTransfer();
            log.info("[{} / {}]\n", soFar, total);
        } while (!transfer.isDone());
        log.info(transfer.getState().name());
    }

    /**
     * 文件上传
     *
     * @param remotePath    远程存储路径
     * @param multipartFile 文件输入流
     * @return 文件存储标识key
     */
    public UploadResult uploads(String remotePath, MultipartFile multipartFile) {
        if (CommonUtils.isEmpty(remotePath)) {
            throw new ApiException("远程存储路径不能为空");
        }
        if (multipartFile == null) {
            throw new ApiException("错误的文件上传参数");
        }
        TransferManager transferManager = transferManager();
        try {
            //设置对象属性
            ObjectMetadata objectMetadata = new ObjectMetadata();
            objectMetadata.setContentLength(multipartFile.getSize());
            if (!CommonUtils.isEmpty(multipartFile.getContentType())) {
                objectMetadata.setContentType(multipartFile.getContentType());
            }
            //设置上传参数
            PutObjectRequest putObjectRequest = new PutObjectRequest(
                    cosBucketName,
                    remotePath,
                    multipartFile.getInputStream(),
                    objectMetadata
            );
            putObjectRequest.setStorageClass(StorageClass.Standard);
            //执行多线程上传并开启监听
            long startTime = System.currentTimeMillis();
            Upload upload = transferManager.upload(putObjectRequest);
            this.showTransferProgress(upload);
            UploadResult uploadResult = upload.waitForUploadResult();
            log.info("上传cos耗时: " + (System.currentTimeMillis() - startTime) / 1000 + "s");
            return uploadResult;
        } catch (Exception e) {
            e.printStackTrace(System.err);
            throw new ApiException("文件上传异常.");
        } finally {
            transferManager.shutdownNow(false);
        }
    }

    /**
     * 文件下载
     *
     * @param remotePath 远程存储路径
     * @param targetFile 目标文件对象
     * @return 结果
     */
    public Download downloads(String remotePath, File targetFile) {
        if (CommonUtils.isEmpty(remotePath)) {
            throw new ApiException("远程存储路径不能为空");
        }
        if (targetFile == null) {
            throw new ApiException("目标存储文件不能为空");
        }
        TransferManager transferManager = transferManager();
        try {
            Download download = transferManager.download(
                    new GetObjectRequest(
                            cosBucketName,
                            remotePath
                    ),
                    targetFile
            );
            download.waitForCompletion();
            return download;
        } catch (Exception e) {
            e.printStackTrace(System.err);
            throw new ApiException("文件下载异常.");
        } finally {
            transferManager.shutdownNow(false);
        }
    }

    /**
     * 文件下载
     *
     * @param remotePath 远程存储路径
     * @return 文件流
     */
    public COSObjectInputStream downloads(String remotePath) {
        if (CommonUtils.isEmpty(remotePath)) {
            throw new ApiException("远程存储路径不能为空");
        }
        try {
            GetObjectRequest getObjectRequest = new GetObjectRequest(
                    cosBucketName,
                    remotePath
            );
            COSObject cosObject = cosClient.getObject(getObjectRequest);
            return cosObject.getObjectContent();
        } catch (CosClientException e) {
            e.printStackTrace(System.err);
            throw new ApiException("文件下载异常.");
        }
    }

}
